package org.dreamwork.jasmine2.web.misc;

import org.dreamwork.jasmine2.events.EventException;
import org.dreamwork.jasmine2.parser.DocumentReader;
import org.dreamwork.jasmine2.parser.ParseException;
import org.dreamwork.jasmine2.parser.Tag;
import org.dreamwork.jasmine2.web.IWebControl;
import org.dreamwork.jasmine2.web.controls.Literal;
import org.dreamwork.jasmine2.web.controls.Panel;
import org.dreamwork.jasmine2.web.controls.WebContainer;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * User: seth.yang
 * Date: 12-6-5
 * Time: 上午10:42
 */
public class IncludeControl extends WebContainer {
    protected Map<String, String> parameters = new HashMap<String, String> ();
    private boolean translate = false;
    private boolean attachUserAgent = false;
    private String url;
    private String method = "GET";
    private String encoding = "UTF-8";

    public IncludeControl () {
        htmlTagName = "";
    }

    public boolean isTranslate () {
        return translate;
    }

    public void setTranslate (boolean translate) {
        this.translate = translate;
    }

    public String getUrl () {
        return url;
    }

    public void setUrl (String url) {
        this.url = url;
    }

    public String getMethod () {
        return method;
    }

    public void setMethod (String method) {
        this.method = method;
    }

    public String getEncoding () {
        return encoding;
    }

    public void setEncoding (String encoding) {
        this.encoding = encoding;
    }

    public boolean isAttachUserAgent () {
        return attachUserAgent;
    }

    public void setAttachUserAgent (boolean attachUserAgent) {
        this.attachUserAgent = attachUserAgent;
    }

    /*
    @Override
    public void createChildControls () {


        childControlCreated = true;
    }
*/

    @Override
    public void render (PrintWriter writer) throws IOException, EventException {
        connect (writer);
    }

    private String getRealUrl () throws IOException {
        String text = url.toLowerCase ();
        String remoteAddress;
        if (text.startsWith ("http://")) {
            remoteAddress = url;
        } else {
            HttpServletRequest request = context.getRequest ();
            String requestURL = request.getRequestURL ().toString ();
            if (text.charAt (0) == '/') {
                URL u = new URL (requestURL);
                remoteAddress = "http://" + u.getHost ();
                if (u.getPort () != u.getDefaultPort ()) remoteAddress += ":" + u.getPort ();
                remoteAddress += url;
            } else {
                int pos = requestURL.lastIndexOf ('/');
                remoteAddress = requestURL.substring (0, pos + 1) + url;
            }
        }

        return remoteAddress;
    }

    private String parseParameters () throws IOException {
        StringBuilder builder = new StringBuilder ();
        for (String key : parameters.keySet ()) {
            if (builder.length () > 0) builder.append ('&');
            String value = parameters.get (key);
            value = URLEncoder.encode (value, "UTF-8");
            builder.append (key).append ('=').append (value);
        }
        return builder.toString ();
    }

    private void connect (PrintWriter writer) throws IOException {
        url = getRealUrl ();
        String parameters = parseParameters ();
        HttpURLConnection conn;
        if ("GET".equalsIgnoreCase (method))
            if (parameters.length () > 0) url += '?' + parameters;

        URL u = new URL (url);
        conn = (HttpURLConnection) u.openConnection ();
        try {
            conn.setDoOutput (true);

            if (attachUserAgent) {
                conn.setRequestProperty ("User-Agent", context.getBrowser ().userAgent);
            } else {
                conn.setRequestProperty ("User-Agent", "");
            }

            if ("POST".equalsIgnoreCase (method)) {
                conn.setDoInput (true);
                OutputStream out = conn.getOutputStream ();
                PrintWriter pw = new PrintWriter (out, true);
                pw.println (parameters);
                pw.flush ();
                out.flush ();
            }

            int responseCode = conn.getResponseCode ();
            if (responseCode != 200) {
/*
                HttpServletResponse response = context.getResponse ();
                response.sendError (responseCode, conn.getResponseMessage ());
*/
                IWebControl control = getErrorMessage (responseCode, conn.getResponseMessage ());
                try {
                    control.render (writer);
                } catch (EventException ex) {
                    ex.printStackTrace ();
                } finally {
                    conn.disconnect ();
                }
                return;
            }

            InputStream in = conn.getInputStream ();
            flushContent (in, writer);
        } catch (ParseException ex) {
            throw new IOException (ex.getMessage ());
        } finally {
            conn.disconnect ();
        }
    }

    private void flushContent (InputStream in, Writer writer) throws IOException, ParseException {
        Reader reader = new InputStreamReader (in, encoding);
        if (translate) {
            DocumentReader dr = new DocumentReader (reader);
            Tag root = dr.parse ();
            translateTag (root);
            writer.write (root.toString ());
            writer.flush ();
        } else {
            char[] buff = new char[1024];
            int length;
            while ((length = reader.read (buff)) != -1) {
                writer.write (buff, 0, length);
                writer.flush ();
            }
        }
    }

    private void translateTag (Tag tag) throws MalformedURLException {
        String name = tag.getName ();
        // check href
        if ("A".equalsIgnoreCase (name) || "LINK".equalsIgnoreCase (name)) {
            String href = tag.getAttribute ("href");
            if (href != null && href.trim ().length () != 0)
                tag.setAttribute ("href", replaceURL (href));
        } else if ("script".equalsIgnoreCase (name) || "IMG".equalsIgnoreCase (name)) { // check src
            String src = tag.getAttribute ("src");
            if (src != null && src.trim ().length () != 0)
                tag.setAttribute ("src", replaceURL (src));
        }

        Tag[] children = tag.getChildren ();
        if (children != null && children.length > 0) for (Tag child : children) {
            translateTag (child);
        }
    }

    private String replaceURL (String address) throws MalformedURLException {
        String text = address.toLowerCase ();
        if (text.startsWith ("http://")) return address;
        if (text.startsWith ("javascript:")) return address;

        URL u = new URL (url);
        String replaced = "http://" + u.getHost ();
        if (u.getPort () != u.getDefaultPort () && u.getPort () != -1)
            replaced += ":" + u.getPort ();
        if (text.charAt (0) == '/')
            return replaced + address;

        int pos = url.lastIndexOf ('/');
        return url.substring (0, pos + 1) + address;
    }

    private IWebControl getErrorMessage (int code, String message) {
        Panel panel = new Panel ();
        panel.init ();
        panel.setStyle ("color", "#f00");
        panel.setStyle ("font-size", "12px");
        panel.setStyle ("overflow", "auto");
        panel.addControl (new Literal (String.format ("%s response %d<br />", message, code)));
        panel.addControl (new Literal ("Error message: " + message));
        return panel;
    }
}